package com.ruoyi.process.pipemaintainence.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.ruoyi.common.id.IdGenerator;
import com.ruoyi.common.utils.BeanUtils;
import com.ruoyi.common.utils.StringUtil;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.util.ShiroUtils;
import com.ruoyi.process.pipemaintainence.domain.BpmnApproval;
import com.ruoyi.process.pipemaintainence.domain.BpmnCopyProcess;
import com.ruoyi.process.pipemaintainence.domain.DrainagePipeMaintainence;
import com.ruoyi.process.pipemaintainence.mapper.DrainagePipeMaintainenceMapper;
import com.ruoyi.process.pipemaintainence.service.BpmnApprovalService;
import com.ruoyi.process.pipemaintainence.service.BpmnCopyProcessService;
import com.ruoyi.process.pipemaintainence.service.IDrainagePipeMainService;
import com.ruoyi.system.domain.SysUser;
import com.ruoyi.system.service.ISysUserService;
import org.activiti.engine.*;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.history.HistoricTaskInstanceQuery;
import org.activiti.engine.impl.identity.Authentication;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.activiti.engine.task.TaskQuery;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * @author zengqingfa
 * @date 2019/11/4 16:35
 * @description
 * @email zengqingfa_java@163.com
 */
@Service
public class DrainagePipeMainServiceImpl implements IDrainagePipeMainService {

    protected static final Logger logger = LoggerFactory.getLogger(DrainagePipeMainServiceImpl.class);

    @Autowired
    private DrainagePipeMaintainenceMapper mapper;

    @Autowired
    private IdentityService identityService;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private TaskService taskService;

    @Autowired
    private HistoryService historyService;

    @Autowired
    private IdGenerator idGenerator;

    @Autowired
    private BpmnCopyProcessService processService;

    @Value("${is.skip.first.node}")
    private Boolean isSkipFirstNode;
    @Autowired
    private BpmnApprovalService bpmnApprovalService;

    @Autowired
    private ISysUserService userService;

    @Autowired
    private BpmnCopyProcessService bpmnCopyProcessService;

    @Override
    public int deleteByPrimaryKey(String id) {
        return mapper.deleteByPrimaryKey(id);
    }

    @Override
    public int insert(DrainagePipeMaintainence record) {
        return mapper.insert(record);
    }

    @Override
    public int insertSelective(DrainagePipeMaintainence record) {
        return mapper.insertSelective(record);
    }

    @Override
    public DrainagePipeMaintainence selectByPrimaryKey(String id) {
        return mapper.selectByPrimaryKey(id);
    }

    @Override
    public int updateByPrimaryKeySelective(DrainagePipeMaintainence record) {
        return mapper.updateByPrimaryKeySelective(record);
    }

    @Override
    public int updateByPrimaryKey(DrainagePipeMaintainence record) {
        return mapper.updateByPrimaryKey(record);
    }

    /**
     * 启动流程
     *
     * @param drainagePipeMaintainence
     * @param userId
     * @param processDefinitionId
     * @return
     */
    @Override
    @Transactional
    public ProcessInstance start(DrainagePipeMaintainence drainagePipeMaintainence, String userId, String processDefinitionId) {
        Map<String, Object> variables = new HashMap<>();
        //先获取id
        String id = drainagePipeMaintainence.getId();
        if (StringUtils.isEmpty(id)) {
            id = idGenerator.getId();
            drainagePipeMaintainence.setId(id);
        }
        //保存业务数据
        drainagePipeMaintainence = save(drainagePipeMaintainence, userId);
        //启动流程
        ProcessInstance processInstance = startProcessInstance(drainagePipeMaintainence, processDefinitionId, userId, variables);
        String processIntanceId = processInstance.getId();
        //启动流程之后，新增记录到抄送人，抄送保存
        copyProcessSave(drainagePipeMaintainence, userId, processDefinitionId, processIntanceId);
        //判断是否需要跳过首节点，直接到下一步的任务
        isSkipFirstNodeComplete(userId, processIntanceId, variables);
        return processInstance;
    }


    /**
     * 判断是否跳过首节点
     *
     * @param userId
     * @param processIntanceId
     * @param variables
     */
    private void isSkipFirstNodeComplete(String userId, String processIntanceId, Map<String, Object> variables) {
        if (isSkipFirstNode) {
            Task task = null;
            TaskQuery query = taskService.createTaskQuery().taskCandidateOrAssigned(userId).active();
            List<Task> todoList = query.list();//获取申请人的待办任务列表
            if (CollUtil.isNotEmpty(todoList)) {
                for (Task tmp : todoList) {
                    if (tmp.getProcessInstanceId().equals(processIntanceId)) {
                        task = tmp;//获取当前流程实例，当前申请人的待办任务
                        break;
                    }
                }
                if (BeanUtils.isNotEmpty(task.getId())) {
                    //保存一份数据到审批意见表中
                    BpmnApproval bpmnApproval = new BpmnApproval();
                    bpmnApproval.setAuditor(userId);
                    bpmnApproval.setTaskDefKey(task.getTaskDefinitionKey());
                    bpmnApproval.setOpinion(true);//设置审批意见
                    bpmnApproval.setCompleteTime(new Date());
                    bpmnApproval.setId(idGenerator.getId());
                    bpmnApproval.setProcDefId(task.getProcessDefinitionId());
                    bpmnApproval.setTaskId(task.getId());
                    bpmnApproval.setProcInstId(task.getProcessInstanceId());
                    bpmnApprovalService.insert(bpmnApproval);
                    taskService.complete(task.getId(), variables);
                }
            }
        }
    }

    /**
     * 抄送流程保存
     *
     * @param drainagePipeMaintainence
     * @param userId
     * @param processDefinitionId
     * @param processInstanceId
     */
    private void copyProcessSave(DrainagePipeMaintainence drainagePipeMaintainence, String userId, String processDefinitionId, String processInstanceId) {
        List<SysUser> receiverList = drainagePipeMaintainence.getReceiverList();
        List<BpmnCopyProcess> list = new ArrayList<>();
        if (CollUtil.isNotEmpty(receiverList)) {
            for (SysUser sysUser : receiverList) {
                BpmnCopyProcess rp = new BpmnCopyProcess();
                rp.setId(idGenerator.getId());
                rp.setCreateBy(userId);
                rp.setCreateTime(new Date());
                rp.setBussinessKey(drainagePipeMaintainence.getId());
                rp.setProcessDefId(processDefinitionId);
                rp.setProcessInstanceId(processInstanceId);
                //设置抄送人id
                rp.setUserId(sysUser.getUserId().toString());
                list.add(rp);
            }
        }
        if (BeanUtils.isNotEmpty(list)) {
            //批量新增抄送
            processService.batchInsert(list);
        }
        //做更新
        String id = drainagePipeMaintainence.getId();
        List<BpmnCopyProcess> copyProcessList = bpmnCopyProcessService.findByBusinessKey(id);
        if (BeanUtils.isNotEmpty(copyProcessList)) {
            for (BpmnCopyProcess process : copyProcessList) {
                process.setUpdateBy(userId);
                process.setUpdateTime(new Date());
                process.setProcessDefId(processDefinitionId);
                process.setProcessInstanceId(processInstanceId);
                bpmnCopyProcessService.updateByPrimaryKeySelective(process);
            }
        }
    }


    /**
     * 启动流程
     *
     * @param drainagePipeMaintainence
     * @param processDefinitionId
     * @param userId
     * @param variables
     * @return
     */
    private ProcessInstance startProcessInstance(DrainagePipeMaintainence drainagePipeMaintainence, String processDefinitionId, String userId, Map<String, Object> variables) {
        String businessKey = drainagePipeMaintainence.getId();
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
        ProcessDefinition processDefinition = processDefinitionQuery.processDefinitionId(processDefinitionId).singleResult();
        // 用来设置启动流程的人员ID，引擎会自动把用户ID保存到activiti:initiator中
        identityService.setAuthenticatedUserId(userId);
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processDefinition.getKey(), businessKey, variables);
        logger.debug("start a processinstance: {}", processInstance);
        String processInstanceId = processInstance.getId();
        drainagePipeMaintainence.setProcessInstanceId(processInstanceId);
        drainagePipeMaintainence.setProcessDefId(processInstance.getProcessDefinitionId());
        //根据主键更新到数据表
        mapper.updateByPrimaryKey(drainagePipeMaintainence);
        logger.debug("start process of {key={}, bkey={}, pid={}, variables={}}", new Object[]{"pipeMaintainence", businessKey, processInstanceId, variables});
        return processInstance;
    }

    /**
     * 保存业务数据
     *
     * @param drainagePipeMaintainence
     */
    private DrainagePipeMaintainence save(DrainagePipeMaintainence drainagePipeMaintainence, String userId) {
        //通过id查询
        DrainagePipeMaintainence dpt = mapper.selectByPrimaryKey(drainagePipeMaintainence.getId());
        if (BeanUtils.isNotEmpty(dpt)) {
            //更新
            drainagePipeMaintainence.setUpdateTime(new Date());
            drainagePipeMaintainence.setUpdateBy(ShiroUtils.getUserId().toString());
            mapper.updateByPrimaryKey(drainagePipeMaintainence);
        } else {
            //新增
            drainagePipeMaintainence.setCreateBy(userId);
            drainagePipeMaintainence.setCreateTime(new Date());
            mapper.insert(drainagePipeMaintainence);
        }
        return drainagePipeMaintainence;
    }

    @Override
    public DrainagePipeMaintainence findByProcessInstanceId(String processInstanceId) {
        return mapper.findByProcessInstanceId(processInstanceId);
    }

    /**
     * 查询某个流程实例是由哪个用户发起的
     *
     * @param taskId
     * @return
     */
    public String getStartedBy(String taskId) {
        HistoricTaskInstanceQuery historicTaskInstanceQuery = historyService.createHistoricTaskInstanceQuery();
        HistoricTaskInstance historicTaskInstance = historicTaskInstanceQuery.taskId(taskId).singleResult();
        String processInstanceId = historicTaskInstance.getProcessInstanceId();
        return getStartedByProcessInstanceId(processInstanceId);
    }


    /**
     * 查询某个流程实例是由哪个用户发起的
     *
     * @param processInstanceId
     * @return
     */
    public String getStartedByProcessInstanceId(String processInstanceId) {
        HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        return historicProcessInstance.getStartUserId();
    }

    @Override
    public DrainagePipeMaintainence findRunningProcessInstanceDetail(String taskId, String status) {
        //获取业务详情
        DrainagePipeMaintainence drainagePipeMaintainence = getDetailByProcessInstanceId(status, taskId);
        //获取发起人和抄送人
        drainagePipeMaintainence = getStartByAndCopyProcessUser(drainagePipeMaintainence, taskId);
        return drainagePipeMaintainence;
    }


    /**
     * 获取发起人和抄送人
     *
     * @param drainagePipeMaintainence
     * @param taskId
     * @return
     */
    private DrainagePipeMaintainence getStartByAndCopyProcessUser(DrainagePipeMaintainence drainagePipeMaintainence, String taskId) {
        String processInstanceId = drainagePipeMaintainence.getProcessInstanceId();
        if (BeanUtils.isNotEmpty(processInstanceId)) {
            String startedBy = getStartedBy(taskId);
            SysUser user = userService.selectUserById(Long.valueOf(startedBy));
            //设置流程是由谁发起的
            drainagePipeMaintainence.setStartByUser(user);
            drainagePipeMaintainence.setTaskId(taskId);
            //设置抄送人
            List<String> receiverList = bpmnCopyProcessService.findReceiverByProceInstanceId(processInstanceId);
            List<SysUser> list = new ArrayList<>();
            if (BeanUtils.isNotEmpty(receiverList)) {
                for (String userId : receiverList) {
                    SysUser sysUser = userService.selectUserById(Long.valueOf(userId));
                    list.add(sysUser);
                }
            }
            drainagePipeMaintainence.setReceiverList(list);
        }
        return drainagePipeMaintainence;
    }

    /**
     * 获取业务详情数据
     *
     * @param status
     * @param taskId
     * @return
     */
    private DrainagePipeMaintainence getDetailByProcessInstanceId(String status, String taskId) {
        String processInstanceId = null;
        DrainagePipeMaintainence drainagePipeMaintainence = new DrainagePipeMaintainence();
        if (status.equals("todo")) {//待办 todo
            TaskQuery taskQuery = taskService.createTaskQuery();
            Task task = taskQuery.taskId(taskId).singleResult();
            processInstanceId = task.getProcessInstanceId();
            drainagePipeMaintainence = mapper.findByProcessInstanceId(processInstanceId);
        }
        if (status.equals("complete")) {     //  ""已办 complete
            HistoricTaskInstance historicTaskInstance = historyService.createHistoricTaskInstanceQuery().taskId(taskId).singleResult();
            processInstanceId = historicTaskInstance.getProcessInstanceId();
            drainagePipeMaintainence = mapper.findByProcessInstanceId(processInstanceId);
            //已办需要回显意见
            BpmnApproval bpmnApproval = bpmnApprovalService.findByTaskId(taskId);
            if (BeanUtils.isNotEmpty(bpmnApproval)) {
                drainagePipeMaintainence.setOpinion(bpmnApproval.getOpinion());//同意/拒绝
                drainagePipeMaintainence.setComment(bpmnApproval.getComment()); //评论 原因
            }
        }
        return drainagePipeMaintainence;
    }


    @Override
    @Transactional
    public void completeTask(String userId, String taskId, Boolean opinion, String comment) {
        Task task = taskService.createTaskQuery().taskId(taskId).taskAssignee(userId).singleResult();
        if (BeanUtils.isEmpty(task)) throw new RuntimeException("任务不存在");
        String taskDefKey = task.getTaskDefinitionKey();
        Map<String, Object> variables = new HashMap<>();
        if (taskDefKey.equals("adjust")) {//调整修改
            variables.put("pipeDepartApproved", opinion);
        }
        if (taskDefKey.equals("confirm")) {//审批确认
            variables.put("pipeDepartManagerApproved", opinion);
        }
        //增加批注信息
        // 由于流程用户上下文对象是线程独立的，所以要在需要的位置设置，要保证设置和获取操作在同一个线程中
        Authentication.setAuthenticatedUserId(userId);//批注人的名称  一定要写，不然查看的时候不知道人物信息
        //办理任务添加批注信息
        if (BeanUtils.isNotEmpty(comment)) {
            taskService.addComment(taskId, task.getProcessInstanceId(), comment);
        }   //comment为批注内容：譬如如一些原因等等
        //保存一份数据到审批意见表中
        BpmnApproval bpmnApproval = new BpmnApproval();
        bpmnApproval.setCreateTime(new Date());
        bpmnApproval.setAuditor(userId);
        bpmnApproval.setAuditor(userId);
        bpmnApproval.setComment(comment);
        bpmnApproval.setTaskDefKey(task.getTaskDefinitionKey());
        bpmnApproval.setOpinion(opinion);//设置审批意见
        bpmnApproval.setCompleteTime(new Date());
        bpmnApproval.setId(idGenerator.getId());
        bpmnApproval.setProcDefId(task.getProcessDefinitionId());
        bpmnApproval.setTaskId(taskId);
        bpmnApproval.setProcInstId(task.getProcessInstanceId());
        bpmnApprovalService.insert(bpmnApproval);
        //说明assignee是该任务的办理人
        taskService.complete(taskId, variables);
    }


}
